package org.sixtythousand.joker.util;

import org.sixtythousand.joker.exception.StopException;

/**
 * @author zhoulk
 * @date 2023/10/11 11:27
 * @desc
 */
public abstract class AbstractLifeCycle implements LifeCycle {
    private final AutoLock lock = new AutoLock();
    private State state = State.STOPPED;

    protected void doStart() {

    }

    protected void doStop() {

    }

    @Override
    public void stop() {
        doStop();
    }

    @Override
    public final void start() {
        try (AutoLock l = lock.lock()) {
            try {
                switch (state) {
                    case STARTED:
                        return;

                    case STARTING:
                    case STOPPING:
                        throw new IllegalStateException(getState());

                    default:
                        try {
                            setStarting();
                            doStart();
                            setStarted();
                        } catch (StopException e) {
                            setStopping();
                            doStop();
                            setStopped();
                        }
                }
            } catch (Throwable e) {
                setFailed(e);
                throw e;
            }
        }
    }

    @Override
    public String getState() {
        return state.toString();
    }

    @Override
    public boolean isStarted() {
        return this.state == State.STARTED;
    }

    @Override
    public boolean isRunning() {
        final State tState = state;
        switch (tState) {
            case STARTED:
            case STARTING:
                return true;
            default:
                return false;
        }
    }

    @Override
    public boolean isStarting() {
        return this.state == State.STARTING;
    }

    @Override
    public boolean isStopping() {
        return this.state == State.STOPPING;
    }

    @Override
    public boolean isStopped() {
        return this.state == State.STOPPED;
    }

    @Override
    public boolean isFailed() {
        return this.state == State.FAILED;
    }

    private void setStarting() {
        state = State.STARTING;
    }

    private void setStarted() {
        state = State.STARTED;
    }

    private void setStopping() {
        state = State.STOPPING;
    }

    private void setStopped() {
        state = State.STOPPED;
    }

    private void setFailed(Throwable th) {
        state = State.FAILED;
    }

}
